#include "board.h"
#include <stdio.h>
#include <windows.h>

struct Board
{
	unsigned int XMax;
	unsigned int YMax;
	unsigned int SlotOccupation[NUMSLOTS];
};

struct Game
{
	unsigned int Turn;
	unsigned int Moves;
	unsigned int State;
	char InfoText[32];
	char WinsText[64];
	unsigned int Num_X_Wins;
	unsigned int Num_O_Wins;
	unsigned int Num_Draws;
	unsigned int AIActive;
	unsigned int X_Last_Move;
};

struct Board Board;
struct Game Game;

void CreateNewBoard(void)
{
	Board.XMax = 300;
	Board.YMax = 300;
	ClearStats();
	sprintf_s(Game.WinsText, 29, "X Wins: 0\tO Wins: 0\tDraws: 0");
	ResetBoard();
	Game.AIActive = 0;
}

void ResetBoard(void)
{
	int i;
	for(i=0; i<NUMSLOTS; i++)
	{
		Board.SlotOccupation[i] = 0;
	}
	Game.Turn = PLAYER_X;
	sprintf_s(Game.InfoText, 16, "Player X's Turn");
	Game.Moves = 0;
	Game.State = IN_PROGRESS;
	Game.X_Last_Move = 0;
}

void DeleteBoard(void)
{

}

unsigned int GetBoardSizeX(void)
{
	return Board.XMax;
}

unsigned int GetBoardSizeY(void)
{
	return Board.YMax;
}

unsigned int GetBoardSlotFromCoords(unsigned int X, unsigned int Y)
{
	unsigned int XSlot = 0;
	unsigned int YSlot = 0;

	if((X >= Board.XMax) || (Y >= Board.YMax))
	{
		return 0;
	}

	if((X < (Board.XMax / 3)))
	{
		XSlot = 1;
	}
	else if((X < (Board.XMax / 3) * 2))
	{
		XSlot = 2;
	}
	else if(X < Board.XMax)
	{
		XSlot = 3;
	}

	if((Y < (Board.YMax / 3)))
	{
		YSlot = 0;
	}
	else if((Y < (Board.YMax / 3) * 2))
	{
		YSlot = 1;
	}
	else if(Y < Board.YMax)
	{
		YSlot = 2;
	}

	return ((YSlot * 3) + XSlot);
}

unsigned int GetOccupation(unsigned int Slot)
{
	return Board.SlotOccupation[Slot-1];
}

unsigned int SetOccupation(unsigned int Slot, unsigned int Player)
{
	if(Board.SlotOccupation[Slot-1] == UNOCCUPIED)
	{
		Board.SlotOccupation[Slot-1] = Player;
		return 1;
	}
	else
	{
		return 0;
	}
}

unsigned int GetCurrentPlayer(void)
{
	return Game.Turn;
}

unsigned int PlayerMove(unsigned int Slot, unsigned int Player)
{
	unsigned int ret = 0;
	if(Slot == 0)
		return 0;
	if(Game.State != IN_PROGRESS)
		return 0;

	if(GetCurrentPlayer() == Player)
	{
		ret = SetOccupation(Slot, Player);
		if(ret)
		{
			Game.Moves++;
			if(Player == PLAYER_X)
			{
				Game.Turn = PLAYER_O;
				Game.X_Last_Move = Slot;
				sprintf_s(Game.InfoText, 16, "Player O's Turn");
			}
			else if(Player == PLAYER_O)
			{
				Game.Turn = PLAYER_X;
				sprintf_s(Game.InfoText, 16, "Player X's Turn");
			}
		}
		else
		{
			sprintf_s(Game.InfoText, 15, "Cannot go here");
		}
		return ret;
	}
	else
	{
		return 0;
	}
}

unsigned int GetCurrentNumMoves(void)
{
	return Game.Moves;
}

static unsigned int CheckThreeInARow(void)
{
	if( (Board.SlotOccupation[0] != UNOCCUPIED && Board.SlotOccupation[0] == Board.SlotOccupation[1] && Board.SlotOccupation[1] == Board.SlotOccupation[2]) || // Top Row
		(Board.SlotOccupation[4] != UNOCCUPIED && Board.SlotOccupation[3] == Board.SlotOccupation[4] && Board.SlotOccupation[4] == Board.SlotOccupation[5]) || // Middle Row
		(Board.SlotOccupation[6] != UNOCCUPIED && Board.SlotOccupation[6] == Board.SlotOccupation[7] && Board.SlotOccupation[7] == Board.SlotOccupation[8]) || // Bottom Row
		(Board.SlotOccupation[0] != UNOCCUPIED && Board.SlotOccupation[0] == Board.SlotOccupation[3] && Board.SlotOccupation[3] == Board.SlotOccupation[6]) || // Left Col
		(Board.SlotOccupation[4] != UNOCCUPIED && Board.SlotOccupation[1] == Board.SlotOccupation[4] && Board.SlotOccupation[4] == Board.SlotOccupation[7]) || // Centre Col
		(Board.SlotOccupation[2] != UNOCCUPIED && Board.SlotOccupation[2] == Board.SlotOccupation[5] && Board.SlotOccupation[5] == Board.SlotOccupation[8]) || // Right Col
		(Board.SlotOccupation[4] != UNOCCUPIED && Board.SlotOccupation[0] == Board.SlotOccupation[4] && Board.SlotOccupation[4] == Board.SlotOccupation[8]) || // Top Left Bottom Right Diag
		(Board.SlotOccupation[4] != UNOCCUPIED && Board.SlotOccupation[2] == Board.SlotOccupation[4] && Board.SlotOccupation[4] == Board.SlotOccupation[6]) )  // Top Right Bottom Left Diag
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

unsigned int CheckForWin(void)
{
	if(CheckThreeInARow())
	{
		if(Game.Turn == PLAYER_X)
		{
			sprintf_s(Game.InfoText, 15, "Player O Wins!");
			Game.State = GAME_WIN_O;
			Game.Num_O_Wins++;
			return GAME_WIN_O;
		}
		else
		{
			sprintf_s(Game.InfoText, 15, "Player X Wins!");
			Game.State = GAME_WIN_X;
			Game.Num_X_Wins++;
			return GAME_WIN_X;
		}
	}
	else
	{
		if(Game.Moves < NUMSLOTS)
		{
			Game.State = IN_PROGRESS;
			return IN_PROGRESS;
		}
		else
		{
			sprintf_s(Game.InfoText, 16, "Game is a Draw!");
			Game.State = GAME_DRAW;
			Game.Num_Draws++;
			return GAME_DRAW;
		}
	}
}

unsigned int GetGameState(void)
{
	return Game.State;
}

void RestartGame(void)
{
	ResetBoard();
}

char * GetInfoString(void)
{
	return (char*)Game.InfoText;
}

char * GetWinsString(void)
{
	sprintf_s(Game.WinsText, 43, "X Wins: %i  O Wins: %i  Draws: %i", Game.Num_X_Wins, Game.Num_O_Wins, Game.Num_Draws);
	return (char*)Game.WinsText;
}

unsigned int GetNumXWins(void)
{
	return Game.Num_X_Wins;
}

unsigned int GetNumOWins(void)
{
	return Game.Num_O_Wins;
}

unsigned int GetNumDraws(void)
{
	return Game.Num_Draws;
}

void ClearStats(void)
{
	Game.Num_X_Wins = 0;
	Game.Num_O_Wins = 0;
	Game.Num_Draws = 0;
}

void AI_Move(void)
{
	unsigned int Slot;
	switch(Game.Moves)
	{
		case 1:
		{
			/* Player has first move. If Corner, go Centre. If Centre, go corner. If side, go centre, or corner next to X, or edge opposite the X */
			if(GetLastXMove() == 5)
			{
				/* centre, go corner */
				Slot = 1;
			}
			else if(GetLastXMove() == 1 || GetLastXMove() == 3 || GetLastXMove() == 7 || GetLastXMove() == 9)
			{
				/* corner, go centre */
				Slot = 5;
			}
			else
			{
				/* side, go centre */
				Slot = 5;
			}
		}
		break;

		case 3:
		{
			if(GetOccupation(5) == PLAYER_X)
			{
				if(GetLastXMove() == 2)
				{
					Slot = 8;
					break;
				}
				if(GetLastXMove() == 3)
				{
					Slot = 7;
					break;
				}
				if(GetLastXMove() == 6)
				{
					Slot = 4;
					break;
				}
				if(GetLastXMove() == 9)
				{
					Slot = 4;
					break;
				}
				if(GetLastXMove() == 8)
				{
					Slot = 2;
					break;
				}
				if(GetLastXMove() == 7)
				{
					Slot = 3;
					break;
				}
				if(GetLastXMove() == 4)
				{
					Slot = 6;
					break;
				}
			}
			else
			{
				if(GetOccupation(1)==PLAYER_X && GetOccupation(3)==PLAYER_X)
				{
					Slot = 2;
					break;
				}
				if(GetOccupation(1)==PLAYER_X && GetOccupation(7)==PLAYER_X)
				{
					Slot = 4;
					break;
				}
				if(GetOccupation(3)==PLAYER_X && GetOccupation(9)==PLAYER_X)
				{
					Slot = 6;
					break;
				}
				if(GetOccupation(7)==PLAYER_X && GetOccupation(9)==PLAYER_X)
				{
					Slot = 8;
					break;
				}
				if(GetOccupation(1)==PLAYER_X && GetOccupation(2)==PLAYER_X)
				{
					Slot = 3;
					break;
				}
				if(GetOccupation(2)==PLAYER_X && GetOccupation(3)==PLAYER_X)
				{
					Slot = 1;
					break;
				}
				if(GetOccupation(1)==PLAYER_X && GetOccupation(4)==PLAYER_X)
				{
					Slot = 7;
					break;
				}
				if(GetOccupation(4)==PLAYER_X && GetOccupation(7)==PLAYER_X)
				{
					Slot = 1;
					break;
				}
				if(GetOccupation(7)==PLAYER_X && GetOccupation(8)==PLAYER_X)
				{
					Slot = 9;
					break;
				}
				if(GetOccupation(8)==PLAYER_X && GetOccupation(9)==PLAYER_X)
				{
					Slot = 7;
					break;
				}
				if(GetOccupation(3)==PLAYER_X && GetOccupation(6)==PLAYER_X)
				{
					Slot = 9;
					break;
				}
				if(GetOccupation(6)==PLAYER_X && GetOccupation(9)==PLAYER_X)
				{
					Slot = 3;
					break;
				}
			}
		}
		break;

		case 5:
		{
			MessageBox(NULL, "AI Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
			return;
		}
		break;

		default:
			MessageBox(NULL, "AI Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
			return;
	}
				
	SetOccupation(Slot, PLAYER_O);
	Game.Moves++;
	Game.Turn = PLAYER_X;
	sprintf_s(Game.InfoText, 16, "Player X's Turn");
}

unsigned int GetAIActiveStatus(void)
{
	return Game.AIActive;
}

unsigned int ToggleAIActive(void)
{
	if(Game.AIActive)
	{
		Game.AIActive = 0;
		return 0;
	}
	else
	{
		Game.AIActive = 1;
		return 1;
	}
}

unsigned int GetLastXMove(void)
{
	return Game.X_Last_Move;
}